﻿using System;
using System.IO;
using System.Net;

namespace USNetFramework.Network
{
    public enum Endianess_Type
    {
        Samll,
        Big,
    }

    public class NetStream
    {
        private MemoryStream m_stream;
        private BinaryReader m_reader;
        private BinaryWriter m_writer;
        private Endianess_Type m_endianess;

        public NetStream(byte[] buffer = null, bool bBigEndianess = false)
        {
            if (buffer == null)
            {
                this.m_stream = new MemoryStream();
            }
            else
            {
                this.m_stream = new MemoryStream(buffer);
            }

            if (bBigEndianess)
            {
                this.m_endianess = Endianess_Type.Big;
            }
            else
            {
                this.m_endianess = Endianess_Type.Samll;
            }

            this.m_reader = new BinaryReader(this.m_stream);
            this.m_writer = new BinaryWriter(this.m_stream);
        }

        public bool SetEndianess(Endianess_Type et)
        {
            if (et == this.m_endianess)
            {
                return false;
            }
            this.m_endianess = et;
            return true;
        }

        public void Close()
        {
            this.m_stream.Close();
            this.m_reader.Close();
            this.m_writer.Close();
        }

        public long ReadInt64()
        {
            long ret = this.m_reader.ReadInt64();
            if (Endianess_Type.Big == this.m_endianess)
            {
                ret = IPAddress.HostToNetworkOrder(ret);
            }
            return ret;
        }

        public int ReadInt32()
        {
            int ret = this.m_reader.ReadInt32();
            if (Endianess_Type.Big == this.m_endianess)
            {
                ret = IPAddress.HostToNetworkOrder(ret);
            }
            return ret;
        }

        public short ReadInt16()
        {
            short ret = this.m_reader.ReadInt16();
            if (Endianess_Type.Big == this.m_endianess)
            {
                ret = IPAddress.HostToNetworkOrder(ret);
            }
            return ret;
        }

        public byte ReadByte()
        {
            return this.m_reader.ReadByte();
        }

        public string ReadString8()
        {
            return System.Text.Encoding.UTF8.GetString
                    (
                        this.m_reader.ReadBytes(ReadByte())
                    );
        }

        public string ReadString16()
        {
            return System.Text.Encoding.UTF8.GetString
                    (
                        this.m_reader.ReadBytes(ReadInt16())
                    );
        }


        /// <summary>
        /// 以buffer的前inLenByte个字节作为读取长度来取buffer
        /// </summary>
        /// <param name="inLenByte">长度占的字节数，支持0,1,2,4，默认为2字节</param>
        /// <returns>读取的buffer</returns>
        public byte[] ReadBuffer(byte inLenByte = 2)
        {
            int readLen = 0;

            switch (inLenByte)
            {
                case 0:
                    break;
                case 1:
                    readLen = ReadByte();
                    break;
                case 4:
                    readLen = ReadInt32();
                    break;
                case 2:
                default:
                    readLen = ReadInt16();
                    break;
            }

            return this.ReadBuffer(readLen);
        }


        /// <summary>
        /// 读取固定字节长度的buffer
        /// </summary>
        /// <param name="inReadLen">读取buffer字节长度</param>
        /// <returns>读取的buffer</returns>
        public byte[] ReadBuffer(int inReadLen)
        {
            if (inReadLen < 1)
            {
                return null;
            }

            return this.m_reader.ReadBytes(inReadLen);
        }


        public long Seek(long offset)
        {
            return this.m_stream.Seek(offset, SeekOrigin.Begin);
        }

        // -------------------------------------------------------------------------------  

        public void WriteByte(byte value)
        {
            this.m_writer.Write(value);
        }


        public void WriteInt16(short value)
        {
            if (Endianess_Type.Big == this.m_endianess)
            {
                value = IPAddress.HostToNetworkOrder(value);
            }
            this.m_writer.Write(BitConverter.GetBytes(value));
        }

        public void WriteInt32(int value)
        {
            if (Endianess_Type.Big == this.m_endianess)
            {
                value = IPAddress.HostToNetworkOrder(value);
            }
            this.m_writer.Write(BitConverter.GetBytes(value));
        }

        public void WriteInt64(long value)
        {
            if (Endianess_Type.Big == this.m_endianess)
            {
                value = IPAddress.HostToNetworkOrder(value);
            }
            this.m_writer.Write(BitConverter.GetBytes(value));
        }

        public void WriteString8(string value)
        {
            WriteByte
            (
                (byte)value.Length
            );


            this.m_writer.Write
            (
                System.Text.Encoding.UTF8.GetBytes(value)
            );
        }


        public void WriteString16(string value)
        {
            WriteInt16
            (
                (short)value.Length
            );


            this.m_writer.Write
            (
                System.Text.Encoding.UTF8.GetBytes(value)
            );
        }

        /// <summary>
        /// 写入一段buffer，buffer前inLenByte个字节代表长度
        /// </summary>
        /// <param name="value">写入的buffer</param>
        /// <param name="inLenByte">长度占的字节数，支持0,1,2,4，默认为2字节</param>
        public void WriteBuffer(byte[] value, byte inLenByte = 2)
        {
            switch(inLenByte)
            {
                case 0:
                    break;
                case 1:
                    WriteByte((byte)value.Length);
                    break;
                case 4:
                    WriteInt32((int)value.Length);
                    break;
                case 2:
                default:
                    WriteInt16((short)value.Length);
                    break;
            }

            this.m_writer.Write
            (
               value
            );
        }

        public byte[] GetBuffer()
        {
            return this.m_stream.ToArray();
        }

        public int GetLength()
        {
            return (int)this.m_stream.Length;
        }
    }
}
